/* eslint no-console: 0, global-require: 0 */
'use strict';
var Benchmark = require('benchmark');
var markdownTable = require('markdown-table');
global.ss = require('simple-statistics');
global.ssMaster = require('../');
global.science = require('science');
global.jStat = require('jstat').jStat;
global.mathjs = require('mathjs');
global.d3 = require('d3-array');

// 我们有一个非常简单的基准测试方法来处理单数组输入的方法，但 jStat 稍微复杂一些 - 你可以通过向方法添加一个布尔参数来指定是否想要 _样本_ 方差。所以我在这里添加它。
global.jStat.sampleVariance = function(input) {
    return global.jStat.variance(input, true);
};

function setupInput() {
    var i;
    var input10 = [];
    for (i = 0; i < 10; i++) {
        input10.push(Math.random());
    }
    var input100 = [];
    for (i = 0; i < 100; i++) {
        input100.push(Math.random());
    }
    var input1000 = [];
    for (i = 0; i < 1000; i++) {
        input1000.push(Math.random());
    }

    var input10a = [];
    for (i = 0; i < 10; i++) {
        input10a.push(Math.random());
    }
    var input100a = [];
    for (i = 0; i < 100; i++) {
        input100a.push(Math.random());
    }
    var input1000a = [];
    for (i = 0; i < 1000; i++) {
        input1000a.push(Math.random());
    }
}

// 这是最终将包含在 readme 中的 markdown 表格的开始部分。
var results = [[
    '', 'ss', 'science', 'jStat', 'mathjs', 'd3', 'ssMaster'
]];

// 这是一个通用的“套件生成器”方法，我们用它来测试不同库执行相同工作的性能 - 第一个参数是一个名称，比如 'median'，第二个参数是一个字符串数组，表示不同库中实现该功能的函数名称。
function suiteForMethods(name, methods, type) {

    var suite = new Benchmark.Suite({
        name: name,
        onError: function(error) {
            console.log(error);
        }
    });

    methods.forEach(function (method) {
        if (type === 'two-arrays') {
            suite.add(method, {
                setup: setupInput,
                fn: method + '(input10, input10a);' + method + '(input100, input100a);' +
                    method + '(input1000, input1000a);'
            });
        } else {
            suite.add(method, {
                setup: setupInput,
                fn: method + '(input10);' + method + '(input100);' + method + '(input1000);'
            });
        }
    });

    suite
        .on('cycle', function(event) {
            console.error(String(event.target));
        })
        .on('complete', function() {
        var row = [name];
        for (var i = 1; i < results[0].length; i++) {
            row[i] = '';
        }
        var fastest = this.filter('fastest')[0];
        this.forEach(function (event) {
            // 这段粗糙的代码决定了每个结果应该放在哪一列，因为我们并不是每个库都有每个方法的实现。
            var idx = results[0].indexOf(event.name.split('.')[1]);
            row[idx] = Math.round(event.hz).toLocaleString();
            if (event === fastest) {
                row[idx] = '**' + row[idx] + '**';
            }
        });
        results.push(row);
    })
    .run();
}

// 这里我们声明了所有将要测试的基本操作，以及每个库中执行这些操作的函数。
var tests = [
    [
        'variance',
        [
            'global.ss.variance',
            'global.ssMaster.variance',
            'global.jStat.variance'
        ]
    ],
    [
        'sampleVariance',
        [
            'global.ss.sampleVariance',
            'global.ssMaster.sampleVariance',
            'global.science.stats.variance',
            'global.jStat.sampleVariance',
            'global.d3.variance'
        ]
    ],
    [
        'covariance',
        [
            'global.ss.sampleCovariance',
            'global.ssMaster.sampleCovariance',
            'global.jStat.covariance'
        ],
        'two-arrays'
    ],
    [
        'skewness',
        [
            'global.ss.sampleSkewness',
            'global.ssMaster.sampleSkewness',
            'global.jStat.skewness'
        ]
    ],
    [
        'geometricMean',
        [
            'global.ss.geometricMean',
            'global.ssMaster.geometricMean',
            'global.jStat.geomean'
        ]
    ],
    [
        'medianAbsoluteDeviation',
        [
            'global.ss.medianAbsoluteDeviation',
            'global.ssMaster.medianAbsoluteDeviation',
            'global.mathjs.mad',
            'global.jStat.meddev'
        ]
    ],
    [
        'median',
        [
            'global.ss.median',
            'global.ssMaster.median',
            'global.mathjs.median',
            'global.jStat.median',
            'global.science.stats.median',
            'global.d3.median'
        ]
    ],
    [
        'mode',
        [
            'global.ss.mode',
            'global.ssMaster.mode',
            'global.mathjs.mode',
            'global.jStat.mode',
            'global.science.stats.mode'
        ]
    ],
    [
        'mean',
        [
            'global.ss.mean',
            'global.ssMaster.mean',
            'global.mathjs.mean',
            'global.jStat.mean',
            'global.science.stats.mode'
        ]
    ],
    [
        'min',
        [
            'global.ss.min',
            'global.ssMaster.min',
            'global.mathjs.min',
            'global.jStat.min',
            'global.d3.min'
        ]
    ],
    [
        'max',
        [
            'global.ss.max',
            'global.ssMaster.max',
            'global.mathjs.max',
            'global.jStat.max',
            'global.d3.max'
        ]
    ],
    [
        'sum',
        [
            'global.ss.sum',
            'global.ssMaster.sum',
            'global.mathjs.sum',
            'global.jStat.sum',
            'global.d3.sum'
        ]
    ]
];

tests.forEach(function (test) {
    suiteForMethods(test[0], test[1], test[2]);
});

// 最后，console.log 输出 readme.md 的内容
console.log('# 基准测试');
console.log('\n\n本文档由 `npm start` 生成。它比较了 simple-statistics 与 JavaScript 中类似库的性能。');
console.log('\n\n' + markdownTable(results));
console.log('\n\n最快的库以粗体显示。数字表示每秒操作次数。');
console.log('\n\nssMaster 是 simple-statistics 的主分支，用于测试和验证 - 它不保证是任何发布的版本。');

console.log('\n\n### 版本\n');

['simple-statistics', 'science', 'jstat', 'mathjs', 'd3-array'].forEach(function (p) {
    console.log('* ' + p + ': ' + require(p + '/package').version);
});